/*
 * Copyright (c) 2010 Marc Poppleton
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.marcpoppleton.strawberry.provider;

import java.util.HashMap;

import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class SetupProvider extends ContentProvider {
	private static final String LOG_TAG = "SetupProvider";
	private static final String DATABASE_NAME = "strawberry.db";
	private static final String COC_TABLE_NAME = "cocs";
	private static final String UNIT_TABLE_NAME = "units";
	private static final int DATABASE_VERSION = 1;

	private static final int SEARCH_COC = 1;
	private static final int COCS = 2;
	private static final int COC_NAME = 3;
	private static final int SEARCH_UNIT = 4;
	private static final int UNITS = 5;
	private static final int UNIT_NAME = 6;

	private static final String AUTHORITY = "strawberry";

	private static final UriMatcher URI_MATCHER;
	static {
		URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		URI_MATCHER.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
				SEARCH_COC);
		URI_MATCHER.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY
				+ "/*", SEARCH_COC);
		URI_MATCHER.addURI(AUTHORITY, COC_TABLE_NAME, COCS);
		URI_MATCHER.addURI(AUTHORITY, COC_TABLE_NAME + "/#", COC_NAME);
		URI_MATCHER.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
				SEARCH_UNIT);
		URI_MATCHER.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY
				+ "/*", SEARCH_UNIT);
		URI_MATCHER.addURI(AUTHORITY, UNIT_TABLE_NAME, UNITS);
		URI_MATCHER.addURI(AUTHORITY, UNIT_TABLE_NAME + "/#", UNIT_NAME);
	}

	private static final HashMap<String, String> SUGGESTION_PROJECTION_MAP;
	static {
		SUGGESTION_PROJECTION_MAP = new HashMap<String, String>();
		SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_1,
				Coc._ID + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
		SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_2,
				Coc.VALUE + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_2);
		SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_1,
				Unit._ID + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
		SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_2,
				Unit.VALUE + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_2);
	}

	private SQLiteOpenHelper mOpenHelper;

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();

		int count;
		switch (URI_MATCHER.match(uri)) {
		case COCS:
			count = db.delete(COC_TABLE_NAME, selection, selectionArgs);
			break;
		case COC_NAME:
			final String segmentCoc = uri.getPathSegments().get(1);
			count = db.delete(COC_TABLE_NAME, Coc._ID
					+ "="
					+ segmentCoc
					+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
							+ ')' : ""), selectionArgs);
			break;
		case UNITS:
			count = db.delete(UNIT_TABLE_NAME, selection, selectionArgs);
			break;
		case UNIT_NAME:
			final String segmentUnit = uri.getPathSegments().get(1);
			count = db.delete(UNIT_TABLE_NAME, Unit._ID
					+ "="
					+ segmentUnit
					+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
							+ ')' : ""), selectionArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		getContext().getContentResolver().notifyChange(uri, null);

		return count;
	}

	@Override
	public String getType(Uri uri) {
		switch (URI_MATCHER.match(uri)) {
		case COCS:
			return "vnd.android.cursor.dir/vnd.org.marcpoppleton.strawberry.provider.strawberry";
		case COC_NAME:
			return "vnd.android.cursor.item/vnd.org.marcpoppleton.strawberry.provider.strawberry";
		case UNITS:
			return "vnd.android.cursor.dir/vnd.org.marcpoppleton.strawberry.provider.strawberry";
		case UNIT_NAME:
			return "vnd.android.cursor.item/vnd.org.marcpoppleton.strawberry.provider.strawberry";
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

	}

	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
		ContentValues values;

		if ((URI_MATCHER.match(uri) != COCS)
				|| (URI_MATCHER.match(uri) != UNITS)) {
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		if (URI_MATCHER.match(uri) == COCS) {
			if (initialValues != null) {
				values = new ContentValues(initialValues);
				values.put(Coc.SORT_NAME, values.getAsString(Coc._ID));
			} else {
				values = new ContentValues();
			}
			SQLiteDatabase db = mOpenHelper.getWritableDatabase();
			final long rowId = db.insert(COC_TABLE_NAME, Coc._ID, values);
			if (rowId > 0) {
				Uri insertUri = ContentUris.withAppendedId(Coc.CONTENT_URI,
						rowId);
				getContext().getContentResolver().notifyChange(uri, null);
				return insertUri;
			}
		}

		if (URI_MATCHER.match(uri) == UNITS) {
			if (initialValues != null) {
				values = new ContentValues(initialValues);
				values.put(Unit.SORT_NAME, values.getAsString(Unit._ID));
			} else {
				values = new ContentValues();
			}
			SQLiteDatabase db = mOpenHelper.getWritableDatabase();
			final long rowId = db.insert(UNIT_TABLE_NAME, Unit._ID, values);
			if (rowId > 0) {
				Uri insertUri = ContentUris.withAppendedId(Unit.CONTENT_URI,
						rowId);
				getContext().getContentResolver().notifyChange(uri, null);
				return insertUri;
			}
		}

		throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public boolean onCreate() {
		Log.w(LOG_TAG, "creating SetupProvider");
		mOpenHelper = new DatabaseHelper(getContext());
		return true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

		switch (URI_MATCHER.match(uri)) {
		case SEARCH_COC:
			qb.setTables(COC_TABLE_NAME);
			final String queryCoc = uri.getLastPathSegment();
			if (!TextUtils.isEmpty(queryCoc)) {
				qb.appendWhere(Coc._ID + " LIKE ");
				qb.appendWhereEscapeString('%' + queryCoc + '%');
				qb.appendWhere(" OR ");
				qb.appendWhere(Coc.VALUE + " LIKE ");
				qb.appendWhereEscapeString('%' + queryCoc + '%');
			}
			qb.setProjectionMap(SUGGESTION_PROJECTION_MAP);
			break;
		case COCS:
			qb.setTables(COC_TABLE_NAME);
			break;
		case COC_NAME:
			qb.setTables(COC_TABLE_NAME);
			qb.appendWhere("_id=" + uri.getPathSegments().get(1));
			break;
		case SEARCH_UNIT:
			qb.setTables(UNIT_TABLE_NAME);
			final String queryUnit = uri.getLastPathSegment();
			if (!TextUtils.isEmpty(queryUnit)) {
				qb.appendWhere(Coc._ID + " LIKE ");
				qb.appendWhereEscapeString('%' + queryUnit + '%');
				qb.appendWhere(" OR ");
				qb.appendWhere(Coc.VALUE + " LIKE ");
				qb.appendWhereEscapeString('%' + queryUnit + '%');
			}
			qb.setProjectionMap(SUGGESTION_PROJECTION_MAP);
			break;
		case UNITS:
			qb.setTables(UNIT_TABLE_NAME);
			break;
		case UNIT_NAME:
			qb.setTables(UNIT_TABLE_NAME);
			qb.appendWhere("_id=" + uri.getPathSegments().get(1));
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		// If no sort order is specified use the default
		String orderBy;
		if (TextUtils.isEmpty(sortOrder)) {
			switch (URI_MATCHER.match(uri)) {
			case SEARCH_COC:
			case COCS:
			case COC_NAME:
				orderBy = Coc.DEFAULT_SORT_ORDER;
				break;
			case SEARCH_UNIT:
			case UNITS:
			case UNIT_NAME:
				orderBy = Unit.DEFAULT_SORT_ORDER;
				break;
			default:
				orderBy = sortOrder;
			}
		} else {
			orderBy = sortOrder;
		}

		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		Cursor c = qb.query(db, projection, selection, selectionArgs, null,
				null, orderBy);
		c.setNotificationUri(getContext().getContentResolver(), uri);

		return c;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}

	private static class DatabaseHelper extends SQLiteOpenHelper {
		DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
			Log.w(LOG_TAG, "creating database helper");
			this.getWritableDatabase();
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL("CREATE TABLE " + COC_TABLE_NAME + "(" + Coc._ID
					+ " TEXT PRIMARY KEY, " + Coc.VALUE + " FLOAT);");
			db.execSQL("CREATE INDEX cocIndexName ON " + COC_TABLE_NAME + "("
					+ Coc.SORT_NAME + ");");
            db.execSQL("CREATE TABLE " + UNIT_TABLE_NAME + "("
            		+ Unit._ID + " TEXT PRIMARY KEY, "
                    + Unit.VALUE + " FLOAT);");
            db.execSQL("CREATE INDEX unitIndexName ON " + UNIT_TABLE_NAME + "(" + Unit.SORT_NAME + ");");			
			populateDb(db);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.w(LOG_TAG, "Upgrading database from version " + oldVersion
							+ " to " + newVersion
							+ ", which will destroy all old data");

			db.execSQL("DROP TABLE IF EXISTS " + COC_TABLE_NAME);
			db.execSQL("DROP TABLE IF EXISTS " + UNIT_TABLE_NAME);
			onCreate(db);
		}

		private void populateDb(SQLiteDatabase db) {
			// inserting basic units measures
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('inches',0.0254);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('feet',0.3048);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('yards',0.9144);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('miles',1609.344);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('mm',0.001);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('cm',0.01);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('meters',1.0);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('decameters',10.0);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('hectometers',100.0);");
        	db.execSQL("INSERT INTO " + UNIT_TABLE_NAME + "(" + Unit._ID + "," + Unit.VALUE + ") VALUES " + "('kilometers',1000.0);");			
			// inserting Canon DSLR values
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 40D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 30D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 20D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 10D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 1000D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 450D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 400D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 350D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 300D',0.019);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 1D',0.023);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 1Ds',0.030);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Canon 5D',0.030);");
			// inserting Nikkon DSLR values
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D700',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D300',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D200',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D100',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D90',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D80',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D70',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D60',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D50',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D40',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D3',0.030);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D2',0.020);");
			db.execSQL("INSERT INTO " + COC_TABLE_NAME + "(" + Coc._ID + ","
					+ Coc.VALUE + ") VALUES " + "('Nikkon D1',0.020);");
		}
	}

}
